package com.gitee.wsl.flowing.actionflow

import com.gitee.wsl.ext.base.allTrue
import com.gitee.wsl.ext.base.anyTrue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext

open class PipeLineFlowImp(
    val context: PipeLineFlowContext = PipeLineFlowContext()
): PipeLineFlow {

    val andActionList = mutableListOf<Action>()

    val anyActionList = mutableListOf<Action>()

    val notActionList = mutableListOf<Action>()

    var ifGotoCall:((context: PipeLineFlowContext)-> Action?)? = null

    override fun all(vararg action: Action) {
        andActionList.addAll(action)
    }

    override fun any(vararg action: Action) {
        anyActionList.addAll(action)
    }

    override fun allNot(vararg action: Action){
        notActionList.addAll(action)
    }

    override suspend fun process(): Boolean = process(context)

    override suspend fun process(context: PipeLineFlowContext): Boolean {

        val gotoAction = ifGotoCall?.invoke(context)

        if(gotoAction != null)
            return gotoAction.process(context)

        var processed = withContext(Dispatchers.Default) {
            val waitList = notActionList.map { action -> async { action.process(context) } }
            val values = awaitAll(*waitList.toTypedArray())
            values.anyTrue()
        }

        if(processed) return false

        processed= withContext(Dispatchers.Default) {
            val waitList = andActionList.map { action -> async { action.process(context) } }
            val values = awaitAll(*waitList.toTypedArray())
            values.allTrue()
        }

        if(!processed) return false

        processed = withContext(Dispatchers.Default) {
            val waitList = anyActionList.map { action -> async { action.process(context) } }
            val values = awaitAll(*waitList.toTypedArray())
            values.anyTrue()
        }

        return processed
    }

    override fun and(action: Action) {
        all(action)
    }

    override fun or(action: Action) {
       any(action)
    }

    override fun not(action: Action) {
        allNot(action)
    }

    override fun ifGoto(actionGoto: (context: PipeLineFlowContext) -> Action?) {
        ifGotoCall = actionGoto
    }

}